package com.example.rabbitmqspringbootdemo;

import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.transaction.RabbitTransactionManager;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

@Configuration
public class RabbitmqConfig {

    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        //生产者配置 MessageConverter 为 Jackson2JsonMessageConverter，以实现JSON序列化
        //rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());

        return rabbitTemplate;
    }


    //消费者配置 MessageConverter 为 Jackson2JsonMessageConverter，以实现JSON反序列化
    //缺省为SimpleMessageConverter，其处理逻辑：
    //如果content_type是以text开头，则把消息转换成String类型
    //如果content_type的值是application/x-java-serialized-object则把消息序列化为java对象，否则，把消息转换成字节数组。
//    @Bean
//    public RabbitListenerContainerFactory<?> rabbitListenerContainerFactory(ConnectionFactory connectionFactory){
//        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
//        factory.setConnectionFactory(connectionFactory);
//        factory.setMessageConverter(new Jackson2JsonMessageConverter());
//        return factory;
//    }

    //与yml中的声明式配置二选一
//    @Bean
//     public ConnectionFactory connectionFactory() {
//            CachingConnectionFactory connection = new CachingConnectionFactory();
//            connection.setAddresses("localhost:5672");
//            connection.setUsername("guest");
//            connection.setPassword("guest");
//            connection.setVirtualHost("/");
//            return connection;
//     }

     //使用代码定义Exchange、Queue、Binding时须配；与yml中的声明式配置二选一
    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
             RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
              //用RabbitAdmin一定要配置这个，spring就会加载这个类================特别重要
              rabbitAdmin.setAutoStartup(true);
               return rabbitAdmin;
     }

    //----------------简单模式----------------
    @Bean
    public Queue simpleQueue(){
        //另外三个参数值缺省为：true(持久化)、false(独占)、false(自动删除队列)
        //第五个可选参数是Map类型，用来设置额外属性。如arguments.put("x-message-ttl", 25000)用来设置25秒自动删除
        return new Queue("springSimpleQueue");
        // return QueueBuilder
        //        .durable("springSimpleQueue")
        //        .build();
    }

    //----------------工作模式----------------
    @Bean
    public Queue workQueue(){
        return new Queue("springWorkQueue");
    }

    //----------------发布订阅模式----------------
    //配置交换器
    @Bean
    public FanoutExchange fanoutExchange() {
        return new FanoutExchange("springFanoutExchange");
    }

    //配置队列
    @Bean
    public Queue fanoutQueue1() {
        return new Queue("springFanoutQueue1", true, false, false, null);
    }

    @Bean
    public Queue fanoutQueue2() {
        return new Queue("springFanoutQueue2", true, false, false, null);
    }
    //配置绑定
    @Bean
    public Binding fanoutBinding1(FanoutExchange fanoutExchange, Queue fanoutQueue1) {
        return BindingBuilder.bind(fanoutQueue1).to(fanoutExchange);
    }

    @Bean
    public Binding fanoutBinding2(FanoutExchange fanoutExchange, Queue fanoutQueue2) {
        return BindingBuilder.bind(fanoutQueue2).to(fanoutExchange);
    }


    //----------------路由模式----------------
    //配置交换器
    @Bean
    public DirectExchange directExchange() {
        return  ExchangeBuilder
                .directExchange("springDirectExchange")
                .durable(true)
                .build();


//        return new DirectExchange("springDirectExchange");
    }

    //配置队列
    @Bean
    public Queue directQueue1() {
        return new Queue("springDirectQueue1", true, false, false, null);
    }

    @Bean
    public Queue directQueue2() {
        return new Queue("springDirectQueue2", true, false, false, null);
    }
    //配置绑定
    @Bean
    public Binding directBinding1(Queue directQueue1, DirectExchange directExchange) {
        return BindingBuilder.bind(directQueue1).to(directExchange).with("one");
    }

    @Bean
    public Binding directBinding2(Queue directQueue2, DirectExchange directExchange) {
        return BindingBuilder.bind(directQueue2).to(directExchange).with("two");
    }


    //----------------通配符模式----------------
    public static final String QUEUE_EMAIL = "queue_email";//email队列
    public static final String QUEUE_SMS = "queue_sms";//sms队列
    public static final String EXCHANGE_NAME="topic.exchange";//topics类型交换器
    public static final String ROUTINGKEY_EMAIL="topic.#.email.#";
    public static final String ROUTINGKEY_SMS="topic.#.sms.#";

    //声明交换器
    @Bean(EXCHANGE_NAME)
    public Exchange exchange(){
        //durable(true) 持久化，mq重启之后交换器还在
        return ExchangeBuilder.topicExchange(EXCHANGE_NAME).durable(true).build();
        // return new TopicExchange(EXCHANGE_NAME);
    }


    /* 声明email和sms队列，用来发送消息
     *   new Queue(QUEUE_EMAIL,true,false,false)：默认参数
     *   durable="true" 持久化 rabbitmq重启的时候不需要创建新的队列
     *   exclusive  该队列仅对首次申明它的连接可见，并在连接断开时自动删除,默认是false
     *   auto-delete 如果该队列没有任何订阅的消费者的话，该队列会被自动删除。这种队列适用于临时队列。 默认是false，
     */
    @Bean(QUEUE_EMAIL)
    public Queue emailQueue(){
        return new Queue(QUEUE_EMAIL);
    }

    //声明sms队列
    @Bean(QUEUE_SMS)
    public Queue smsQueue(){
        return new Queue(QUEUE_SMS);
    }

    //ROUTINGKEY_EMAIL队列绑定交换器，指定routingKey
    @Bean
    public Binding bindingEmail(@Qualifier(QUEUE_EMAIL) Queue queue,
                                @Qualifier(EXCHANGE_NAME) Exchange exchange){
        return BindingBuilder.bind(queue).to(exchange).with(ROUTINGKEY_EMAIL).noargs();
    }

    //ROUTINGKEY_SMS队列绑定交换器，指定routingKey
    @Bean
    public Binding bindingSMS(@Qualifier(QUEUE_SMS) Queue queue,
                              @Qualifier(EXCHANGE_NAME) Exchange exchange){
        return BindingBuilder.bind(queue).to(exchange).with(ROUTINGKEY_SMS).noargs();
    }

}


